package com.google.appengine.a4ieve.servlets.resources;

import com.google.appengine.a4ieve.*;
import com.google.appengine.a4ieve.entities.AchievementWrapper;
import com.google.appengine.a4ieve.entities.StudentWrapper;
import com.google.appengine.api.datastore.*;
import com.google.appengine.api.users.UserServiceFactory;
import org.json.JSONArray;
import org.json.JSONObject;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.logging.Logger;

/**
 * User: lunin
 * Date: 4/24/14
 * Time: 10:51 AM
 */
public class GetAchievementsServant implements Servant {

    private static final Logger LOG = Logger.getLogger(GetCuratorServant.class.getName());

    private static final String POSITIVE = "positive";
    private static final String NEGATIVE = "negative";

    @Override
    public void process(HttpServletRequest req, HttpServletResponse resp) {
        DatastoreService store = DatastoreServiceFactory.getDatastoreService();
        JSONObject requestJson = (JSONObject) req.getAttribute(Const.INNER_JSON);
        int page = 0;
        int count = 0;
        if (requestJson.has(Const.PAGE) && requestJson.has(Const.COUNT)) {
            page = Integer.parseInt((String) requestJson.get(Const.PAGE));
            count = Integer.parseInt((String) requestJson.get(Const.COUNT));
        }
        if (page == 0 && count == 0) {
            //simply get all achievements
            String userName = Helper.cropEmailId(UserServiceFactory.getUserService().getCurrentUser().getEmail());
            Query achievementQuery = new Query(AchievementWrapper.KIND_KEY).addFilter(
                    AchievementWrapper.USER_ID_PROPERTY,
                    Query.FilterOperator.EQUAL,
                    userName
            ).setKeysOnly();
            List<Entity> output = store.prepare(achievementQuery).asList(FetchOptions.Builder.withDefaults());
            JSONArray data = new JSONArray();
            try {
                JSONArray achievements = new JSONArray();
                for (Entity e : output) {
                    Entity toWrap = store.get(e.getKey());
                    if (toWrap.getProperty(AchievementWrapper.APPROVED_BY) != null) {
                        AchievementWrapper newWrapper = new AchievementWrapper(toWrap);
                        achievements.put(newWrapper.toJson());
                    }
                }
                data.put(achievements);
//                for (StudentGroup group : StudentGroup.values()) {
                Query groupPositiveCounter = new Query(AchievementWrapper.KIND_KEY).setKeysOnly();
                List<Entity> entities = store.prepare(groupPositiveCounter).asList(FetchOptions.Builder.withDefaults());
                LOG.info("Start recording" + System.currentTimeMillis());
                Map<String, int[]> groupCounts = new HashMap<String, int[]>();
                for (Entity e : entities) {
                    e = store.get(e.getKey());
                    String group = (String)e.getProperty(AchievementWrapper.GROUP_PROPERTY);
                    if (!groupCounts.containsKey(group)) {
                        int[] initializer = {0, 0};
                        groupCounts.put(group, initializer);
                    }
                    String status = (String)e.getProperty(AchievementWrapper.STATUS_PROPERTY);
                    if (AchievementClass.EARNED.getClassId().equals(status)) {
                        long isPositive = (Long)e.getProperty(AchievementWrapper.IS_POSITIVE);
                        if (isPositive == 1) {
                            groupCounts.get(group)[0] = groupCounts.get(group)[0]+1;
                        } else {
                            groupCounts.get(group)[1] = groupCounts.get(group)[1]+1;
                        }
                    }
                }
                LOG.info("End recording " + System.currentTimeMillis());
                for (Map.Entry<String, int[]> out : groupCounts.entrySet()) {
                    JSONObject countObject = new JSONObject();
                    countObject.put(Const.GROUP, out.getKey());
                    countObject.put(POSITIVE, out.getValue()[0]);
                    countObject.put(NEGATIVE, out.getValue()[1]);
                    data.put(countObject);
                }
                resp.setContentType("text/json;charset=UTF-8");
//                Helper.writeEntitiesToJson(AchievementWrapper.class, output, output.size(), store).write(resp.getWriter());
                data.write(resp.getWriter());
                return;
            } catch (IOException i) {
                LOG.severe("Error while writing curator information " + i);
            } catch (EntityNotFoundException e) {
                LOG.severe("Entity not found");
            }
        }
        List<Entity> achievementEntities = new LinkedList<Entity>();
        String groupId = (String) req.getSession().getAttribute(Const.GROUP);
        Query studentQuery = new Query(StudentWrapper.KIND_KEY).addFilter(
                StudentWrapper.GROUP_KEY_PROPERTY,
                Query.FilterOperator.EQUAL,
                groupId
        );
        List<Entity> students = store.prepare(studentQuery).asList(FetchOptions.Builder.withDefaults()); //I hope there ain't much overhead
        Set<String> studentIds = new HashSet<String>();
        for (Entity stud : students) {
            studentIds.add((String) stud.getProperty(StudentWrapper.USER_ID_PROPERTY));
        }
        LOG.severe("Student ids to load: " + studentIds);
        Query achievementQuery = new Query(AchievementWrapper.KIND_KEY).addFilter(
                AchievementWrapper.USER_ID_PROPERTY,
                Query.FilterOperator.IN,
                studentIds)
                .addSort(AchievementWrapper.USER_ID_PROPERTY)
                .addSort(AchievementWrapper.ACHIEVEMENT_NAME).setKeysOnly();
        FetchOptions options = FetchOptions.Builder.withDefaults();
        if (page != 0 && count != 0) {
            options = FetchOptions.Builder.withOffset((page - 1) * count).limit(count);
        }
        achievementEntities = store.prepare(achievementQuery).asList(options);
        for (Entity a : achievementEntities) {
            LOG.severe("Loading achievement " + a.getProperty(AchievementWrapper.ACHIEVEMENT_NAME));
        }
        Query totalCountQuery = new Query(AchievementWrapper.KIND_KEY).addFilter(
                AchievementWrapper.USER_ID_PROPERTY,
                Query.FilterOperator.IN,
                studentIds);
        int total = store.prepare(totalCountQuery).countEntities(FetchOptions.Builder.withDefaults());
        try {
            resp.setContentType("text/json;charset=UTF-8");
            JSONArray output = Helper.writeEntitiesToJson(AchievementWrapper.class, achievementEntities, total, store);
            JSONObject currentUser = new JSONObject();
            currentUser.put(Const.USER, Helper.cropEmailId(UserServiceFactory.getUserService().getCurrentUser().getEmail()));
            output.put(currentUser);
            output.write(resp.getWriter());
        } catch (IOException i) {
            LOG.severe("Error while writing curator information " + i);
        }
    }
}
